-- Making the license a package comment causes it to be part of every
-- runnable frege code.
{--
    Copyright © 2011 - 2021, Ingo Wechsung
 
    All rights reserved.
 
    Redistribution and use in source and binary forms, with or
    without modification, are permitted provided that the following
    conditions are met:

    -   Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.

    -   Redistributions in binary form must reproduce the above
        copyright notice, this list of conditions and the following
        disclaimer in the documentation and/or other materials provided
        with the distribution. 

    -   Neither the name of the copyright holder
        nor the names of its contributors may be used to endorse or
        promote products derived from this software without specific
        prior written permission.
 
    *THIS SOFTWARE IS PROVIDED BY THE
    COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
    USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
    AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
    THE POSSIBILITY OF SUCH DAMAGE.*
-}

{--
 *
 * This package provides basic definitions for the Frege language.
 *
 * The _Prelude_ packages are imported explicitly or implicitly during compilation
 * of any other package.
 * They define basic data structures, classes and functions.
 *
 * The types and constructors for lists, unit type and tuple types are not
 * defined here: They are provided programmatically by the compiler when it
 * compiles a package with the name @frege.prelude.PreludeBase@. Nevertheless, they are
 * considered part of the _Prelude_, thus qualified names like '(,)'
 * are okay.
 *
 * The packages are _implementation specific_ insofar as the compiler may
 * assume that certain items are defined here in a certain way.
 * Changes may thus lead
 * to compiler crashes or java code that will be rejected by the java compiler.
 -}


{-
Uncommon characters defined here:

> Char   used for               howto type   in editor
> •      function composition   ALT+0149     CTRL+.
> «      left shift?            ALT+0171     CTRL+<
> »      right shift?           ALT+0187     CTRL+Shift+<
> ¦      to be determined       ALT+0166     Alt+Shift+<
> ¿      to be determined       ALT+0191     CTRL+ß (?)
> ´      regular expressions    ALT+0180
>
-}

protected module frege.prelude.PreludeBase 
    inline candidates (otherwise, const, asTypeOf, $!, $, flip, curry, und, oder,
        chr, bool,
        ST.>>=,
        Int.fromInt, Double.fromDouble,
        Int.even, Long.even, Int.odd, Long.odd
        ) 
    where


{-
 * Here are the standard operators in precedence order
 * (higher numbers bind more tightly)
 * This is so that @!x@ can be thought of having
 * precedence 18 and @(f x)@ can be thought of as having precedence 17
 -}


infixr 15 `^`
infixl 14 `*` `/` `mod` `rem` `div` `quot`
infixl 13 `+`  -
infixr 13 `++`
infixl 12 `shiftL` `shiftR` `rotateL` `rotateR` `ushiftR`
infixl 11 `.&.`
infixl 10 `.|.` `.^.` 
infix  9 `<=` `>=` `<` `>` 
infix  8 `<=>` `compare`
infix  7 `==` `!=`  `===` `!==` -- `<>`
infixr 6 `&&`  `und`
infixr 5 `||`  `oder` `^^` 
infixr 4 `:` `!:`
infixl 3 `>>=`                   -- monad bind
infixr 2 `@` `seq`               -- so that x@a:bs is parsed as x@(a:bs)
infixl 2 either 
infixl 1 on
infixr 1 `$` `$!`

-- -----------------------------------------------------------------------------
--          CLASS SECTION
-- -----------------------------------------------------------------------------

{-- 
  The type class 'Eq' provides operators '==', '!=' and 'hashCode'.
  
  All types whose values can be compared for equality should be instances of
  this class. For algebraic data types instances can be automatically derived
  if all components are themselves instances of 'Eq'.
  -}
class Eq e where
    --- Check for equality. This function is required in all instances.
    --- The basic law of philosophy
    --- > a == a
    --- shall be obeyed by all implementations.
    (==) :: e -> e -> Bool               -- must be defined in instances
    --- Check for inequality. The default implementation obeys the laws
    --- > !(a != a)
    --- > (a != b) == !(a == b)
    --- > (a == b) != (a != b)
    --- These laws shall also be obeyed in all implementations.
    (!=) :: e -> e -> Bool
    a!=b =  if a==b then false else true   -- may be replaced by more efficient version
    --- Compute a hash code. 
    --- The following rules shall hold in all instances:
    --- > a == b ==> hashCode a == hashCode b
    --- > hashCode a != hashCode b ==> a != b
    --- In addition, unequal values should produce unequal hash codes more likely than not.
    {--
        The hash code in derived instances for algebraic data types is computed as follows:
        > hashCode v = case v of
        >    Con_1 f_1 ... f_k -> fold mkhash 1 [1, hashCode f_1, ..., hashCode f_k ]
        >    ...
        >    Con_n f_1 ... f_k -> fold mkhash 1 [n, hashCode f_1, ..., hashCode f_k ]
        >   where mkhash a b = (31 * a) + b
        Here, the @Con_i@ with @i>0@ are the constructors, and in each clause
        the @f_j@ with @j >= 0@ are bound to the fields of the constructor under
        consideration.
    -}
    hashCode :: e -> Int


instance Eq Bool where
    pure native == :: Bool -> Bool -> Bool
    pure native != :: Bool -> Bool -> Bool
    hashCode true  = 1
    hashCode false = 0



{--
 * Determines the constructor of a value.
 * This is used like
 * >constructor arg
 * where @arg@ is any frege value.
 *
 * Returns 0 for function types, product types and native types or
 * the _constructor number_ for constructed types. The _constructor number_
 * is a small integer associated with every constructed value. It indicates
 * the data constructor a value was constructed with.
 *
 * The compiler assigns constructor numbers starting from 0 to the constructors
 * defined in a @data@ definition in the order of their appearance.
 *
 * Examples
 * >constructor [] == 0
 * >constructor (a:as) == 1
 * >constructor "string"  == 0    // native value
 *
 * This function is strict in its argument, i.e.
 * >constructor undefined == undefined
 *
 * *Implementation specific:* This function is used in derived instances
 * of 'Eq' and 'Ord'.
 -}
pure native constructor "frege.run.RunTM.constructor" {} :: a -> Int


--######### Basic types      ####################
{--
    'Bool' values are based on Java's primitive @boolean@ values.
    Note that @true@ and @false@ are literals, not constructors.
 -}
data Bool = native boolean

{--
    For compatibility with Haskell, the 'HaskellBool' type defines
    constructors 'True' and 'False'.

    When the identifiers @True@ or @False@ are used in patterns or expressions, 
    qualified or unqualified, and name resolution detects that they
    resolve to 'PreludeBase.HaskellBool.True' or 'PreludeBase.HaskellBool.False'
    they will be replaced by literals @true@ or @false@.

    This is, of course, a hack, but I see no other way to bridge the gap between
    redefinable constructor ids and literals. For example, we couldn't simply
    define @True@ as another literal keyword, because some Haskell code 
    might use @Prelude.True@ or could have code like.
    
    > import Prelude hiding(True, False)
    > data TriBool = False | Perhaps | True 
-}
data HaskellBool = False     --- will be replaced by literal @false@
                 | True      --- will be replaced by literal @true@

{--
This is a constant with the value @true@.
It is most often used as the last alternative in pattern guards:

> foo n | n >= 0    = ...
>       | otherwise = ...
-}
otherwise = true

{--
warning: will soon be replaced with bool
This is used by code generation when a conditional expression
appears in a lazy context, i.e.
> (42, if foo then bar else baz)
@lazyif a b c@ evaluates to @b@ if @a@ is @true@, otherwise to @c@.
-}
lazyif a b c = if a then b else c

{--
This is used by code generation when a conditional expression
appears in a lazy context, i.e.
> (42, if foo then bar else baz)
@bool a b c@ evaluates to @a@ if @c@ is @true@, otherwise to @b@.
-}
bool a b c = if c then a else b

{--
    'Int' values are based on Java's primitive @int@ values.

    The existence of this type is assumed in numerous places in the compiler.

    Like with all @native@ Java types, be they primitive or reference types,
    Frege holds the raw @int@ in boxed form. However, in certain cases the
    compiler will optimize the boxing away:
    - Strict variables or function arguments work with the unboxed value directly.
    - Functions with a @native@ return type generally return the unboxed value.
    Polymorphic data structures or functions always work with boxed values.
    Thus, for example, the function
    > sum a b c = a + b + c
    can compute the sum of 3 'Int's, 'Long's, 'Double's or any other values
    of a type that is an instance of type class 'Num', but it may be somewhat
    slower than functions specialized for a given type.

    According to the Java Language Specification, @int@ values are
    32 bit wide signed two's complement integers (§4.2). Java operations on @int@ do
    not indicate overflow or underflow in any way (§4.2.2). Instead, just the low 32 bits of
    every result are retained.
 -}
data Int = native int where
    --- convert an 'Int' to a 'Float', i.e. @2.float == 2.0f@.
    --- For large integers, the result may have been be rounded.
    pure native float java.lang.Float.valueOf ::    Int -> Float
    --- convert an 'Int' to a 'Double', i.e. @2.double == 2.0@.
    pure native double java.lang.Double.valueOf ::  Int -> Double
    --- Convert an 'Int' to a 'Long', i.e. @2.long == 2L@.
    pure native long java.lang.Long.valueOf ::      Int -> Long
    --- @i.char@ returns the 'Char' value whose ordinal number is @i@
    --- Result is only valid for integers in the range 0..65535
    pure native char "(char)"  ::            Int -> Char
    --- Computes binary /or/ of two integers. Uses the java @|@-operator.
    pure native (.|.)  "|" :: Int -> Int -> Int
    --- Computes binary /exclusive or/ of two integers. Uses the java @^@-operator.
    pure native (.^.) "^" :: Int -> Int -> Int
    --- Computes binary /and/ of two integers. Uses the java @&@-operator.

    pure native (.&.) "&" :: Int -> Int -> Int

    --- The number of bits used to represent an int value in two's complement binary form
    pure native size java.lang.Integer.SIZE :: Int

    pure native shiftL "<<" :: Int -> Int -> Int
    pure native shiftR ">>" :: Int -> Int -> Int
    --- unsigned right shift
    pure native ushiftR ">>>" :: Int -> Int -> Int
    pure native complement "~" :: Int -> Int

    --- Returns the value obtained by rotating the two's complement binary representation of the specified int value left
    --- by the specified number of bits.
    pure native rotateL java.lang.Integer.rotateLeft :: Int -> Int -> Int

    --- Returns the value obtained by rotating the two's complement binary representation of the specified int value
    --- right by the specified number of bits.
    pure native rotateR java.lang.Integer.rotateRight :: Int -> Int -> Int

    -- Compare 2 integers, use java operator
    -- pure native (==) :: Int -> Int -> Bool   // is defined in Eq
    --- convert to a hexadecimal string
    pure native toHexString java.lang.Integer.toHexString :: Int -> String
    --- The 'hashCode' of an 'Int' is the identity
    hashCode i = i

{--
 * 'Integer' is
 * a type for integer numbers of unlimited size,
 * It has instances for 'Eq', 'Ord', 'frege.prelude.PreludeText#Show' and 'Integral'.

 * This is derived from @java.math.BigInteger@.
 -}


data Integer = native java.math.BigInteger where
    -- constants
    pure  native zero    java.math.BigInteger.ZERO    :: Integer
    pure  native one     java.math.BigInteger.ONE     :: Integer
    pure  native ten     java.math.BigInteger.TEN     :: Integer
    --- construction from a 'Long', see also 'String.aton' and 'String.integer'
    pure  native valueOf java.math.BigInteger.valueOf :: Long -> Integer
    -- arithmetic operations
    pure  native +       add                          :: Integer -> Integer -> Integer
    pure  native *       multiply                     :: Integer -> Integer -> Integer
    pure  native -       subtract                     :: Integer -> Integer -> Integer
    pure  native quot    divide                       :: Integer -> Integer -> Integer
    pure  native rem     remainder                    :: Integer -> Integer -> Integer
    --- _Warning_! Throws @ArithmeticException@ when divisor is negative.
    pure  native nMod    mod                          :: Integer -> Integer -> Integer
    pure  native abs                                  :: Integer -> Integer
    pure  native negate                               :: Integer -> Integer
    -- relational
    pure  native compareTo                            :: Integer -> Integer -> Int
    pure  native max                                  :: Integer -> Integer -> Integer
    pure  native min                                  :: Integer -> Integer -> Integer
    -- shift
    pure  native shiftR    shiftRight                 :: Integer -> Int -> Integer
    pure  native shiftL    shiftLeft                  :: Integer -> Int -> Integer
    --- unsigned right shift on big integers does not really make sense ...
    b `ushiftR` i = abs b `shiftR` i
    -- bit arithmetic
    pure  native (.|.)     or                         :: Integer -> Integer -> Integer
    pure  native (.&.)    and                         :: Integer -> Integer -> Integer
    pure  native (.^.)    xor                         :: Integer -> Integer -> Integer
    pure  native complement   not                     :: Integer -> Integer
    -- miscellaneous
    --- Returns the number of bits in the minimal two's-complement representation of this 'Integer', excluding a sign bit.
    pure native bitLength                             :: Integer -> Int
    pure native toString                              :: Integer -> String
    pure native sign    signum                        :: Integer -> Int
    pure native long    longValue                     :: Integer -> Long
    pure native int     intValue                      :: Integer -> Int
    pure native double  doubleValue                   :: Integer -> Double
    pure native hashCode                              :: Integer -> Int
    pure native gcd                                   :: Integer -> Integer -> Integer

{--
 * 'Long' values are based on Java's primitive @long@ values.
 *
 * According to the Java Language Specification, @long@ values are
   64 bit wide signed two's complement integers (§4.2). Java operations on @long@ do
   not indicate overflow or underflow in any way (§4.2.2). Instead, just the low 64 bits of
   every result are retained.
 -}
data Long = native long  where
    --- Convert an 'Long' to a 'Float', i.e. @42L.float == 42.0f@.
    --- For large numbers, the result may have been be rounded.
    pure native float java.lang.Float.valueOf ::   Long -> Float
    --- Convert an 'Long' to a 'Double', i.e. @42L.double == 42.0@.
    --- For large numbers, the result may have been be rounded.
    pure native double java.lang.Double.valueOf :: Long -> Double
    --- Uses a java cast to convert a 'Long' to an 'Int'. This is a _narrowing primitive conversion_ in java parlance.
    pure native int "(int)"  ::          Long -> Int
    --- Computes binary _or_ of two long integers. Uses the java @|@-operator.
    pure native (.|.)  "|" :: Long -> Long -> Long
    --- Computes binary _exclusive or_ of two long integers. Uses the java @^@-operator.
    pure native (.^.) "^" :: Long -> Long -> Long
    --- Computes binary _and_ of two integers. Uses the java @&@-operator.
    pure native (.&.) "&" :: Long -> Long -> Long

    pure native shiftL "<<" :: Long -> Int -> Long

    pure native shiftR ">>" :: Long -> Int -> Long

    --- unsigned right shift
    pure native ushiftR ">>>" :: Long -> Int -> Long

    pure native complement "~" :: Long -> Long

    --- Returns the value obtained by rotating the two's complement binary representation
    --- of the specified long value left by the specified number of bits.
    pure native rotateL java.lang.Long.rotateLeft :: Long -> Int -> Long

    --- Returns the value obtained by rotating the two's complement binary representation
    --- of the specified long value right by the specified number of bits.
    pure native rotateR java.lang.Long.rotateRight :: Long -> Int -> Long

    pure native size java.lang.Long.SIZE :: Int

    --- hash code is upper half and lower half xor'ed
    hashCode l = (int l) Int.`.^.` (int (l `shiftR` 32))

--- 'Char' values are based on Java's primitive @char@ values.
--- This type has many native functions based on the methods in @java.lang.Character@. 
--- Most @is...@ functions work on 'Char'  and 'Int' (codepoint).
--- Likewise, most @to...Case@ functions work on codepoints.
data Char = native char where
    {--
     * @c.ord@ is the ordinal (integer) value of the character @c@.
     * It holds: @c.ord.char@ == @c@, see 'Int.char'.
     * (But note that @i.char.ord@ is not necessarily @i@)
     -}
    pure native ord "(int)"                                         :: Char -> Int
    pure native hashCode "(int)"                                    :: Char -> Int
    pure native isLowerCase     java.lang.Character.isLowerCase     :: Char -> Bool
                                                                     | Int  -> Bool

    --- The lowercase equivalent of the character, if any; otherwise, the character itself.
    pure native toLowerCase     java.lang.Character.toLowerCase     :: Char -> Char
                                                                     | Int  -> Int

    pure native isUpperCase     java.lang.Character.isUpperCase     :: Char -> Bool
                                                                     | Int  -> Bool

    --- The uppercase equivalent of the character, if any; otherwise, the character itself.
    pure native toUpperCase     java.lang.Character.toUpperCase     :: Char -> Char
                                                                     | Int  -> Int

    --- The titlecase equivalent of the character, if any; otherwise, the character itself.
    pure native toTitleCase     java.lang.Character.toTitleCase     :: Char -> Char
                                                                     | Int  -> Int
    pure native isWhitespace    java.lang.Character.isWhitespace    :: Char -> Bool
                                                                     | Int  -> Bool
    pure native isLetterOrDigit java.lang.Character.isLetterOrDigit :: Char -> Bool
                                                                     | Int  -> Bool
    pure native isDigit         java.lang.Character.isDigit         :: Char -> Bool
                                                                     | Int  -> Bool
    --- Returns the numeric value of the character argument in the specified radix.
    --- If the character is not a digit in the given radix, -1 is returned.
    --- The radix must be in the range 2..36, otherwise also -1 is returned.
    pure native digit           java.lang.Character.digit           ∷  Char → Int → Int

    --- > Char.forDigit d r
    --- returns the character for the digit _d_ in radix _r_
    --- _d_ must not be negative and lower than _r_, and _r_ must be in the range 2..36
    --- When the arguments are invalid the character \'\u0000\' is returned.
    pure native forDigit        java.lang.Character.forDigit        ∷  Int  → Int → Char

    pure native isLetter        java.lang.Character.isLetter        :: Char -> Bool
                                                                     | Int  -> Bool
    {--
        Determines if the specified character is an ISO control character. 
        A character is considered to be an ISO control character if its code is 
        in the range "\u0000" through "\u001F" 
        or in the range "\u007F" through "\u009F".
    -}
    pure native isISOControl    java.lang.Character.isISOControl    :: Char → Bool
                                                                     | Int  → Bool
    {--
        Determines if the given char value is a Unicode surrogate code unit.

        Such values do not represent characters by themselves, 
        but are used in the representation of supplementary characters 
        in the UTF-16 encoding.

        A char value is a surrogate code unit if and only if 
        it is either a low-surrogate code unit or a high-surrogate code unit.
    -}
    pure native isSurrogate     java.lang.Character.isSurrogate     ∷ Char → Bool

    {--
        Determines if the given char value is a Unicode low-surrogate code unit 
        (also known as trailing-surrogate code unit).

        Such values do not represent characters by themselves, 
        but are used in the representation of supplementary characters in the UTF-16 encoding.
    -}
    pure native isLowSurrogate  java.lang.Character.isLowSurrogate  ∷ Char → Bool

    {--
        Determines if the given char value is a Unicode high-surrogate code unit 
        (also known as leading-surrogate code unit).

        Such values do not represent characters by themselves, 
        but are used in the representation of supplementary characters in the UTF-16 encoding.
    -}
    pure native isHighSurrogate java.lang.Character.isHighSurrogate ∷ Char → Bool
    
    {--
        Determines whether the specified character (Unicode code point) 
        is in the supplementary character range.
        
        This is roughly equivalent to
        
        > (> ord Char.maxBound)
        
        except that it also checks if the value is lower than @0x110000@
        
        If, for some integer @n@
        
        > not (Char.isSupplementaryCodePoint n) && (n > ord Char.maxBound)
        
        then @n@ is not a codepoint at all. 
    -}
    pure native isSupplementaryCodePoint    
                    java.lang.Character.isSupplementaryCodePoint    :: Int -> Bool
    
    --- Determines whether the specified code point is a valid Unicode code point value.
    --- This is the case if it is not negative and lower than @0x110000@
    pure native isValidCodePoint
                    java.lang.Character.isValidCodePoint            :: Int -> Bool
    {--
        Determines if a character (Unicode code point) is defined in Unicode.
        
        A character is defined if at least one of the following is true:

        - It has an entry in the UnicodeData file.
        - It has a value in a range defined by the UnicodeData file.
    -}
    pure native isDefined
                    java.lang.Character.isDefined                   :: Char -> Bool
                                                                     | Int  -> Bool
    {--
        The leading surrogate (which is a high surrogate code unit) of the
        surrogate pair representing the specified supplementary character
        (Unicode code point) in the UTF-16 encoding. 
        
        If the specified value is not a supplementary character, 
        an unspecified character is returned.
        
        See also: 'Char.isSupplementaryCodePoint', 'Char.lowSurrogate', 'Char.toCodePoint'
        
        The following holds:
        
        > isSupplementaryCodePoint x ==> (x == toCodePoint (highSurrogate x) (lowSurrogate x))
    -}
    pure native highSurrogate  java.lang.Character.highSurrogate   :: Int -> Char

    {--
        The trailing surrogate (which is a low surrogate code unit) of the
        surrogate pair representing the specified supplementary character
        (Unicode code point) in the UTF-16 encoding. 
        
        If the specified value is not a supplementary character, 
        an unspecified character is returned.
        
        See also: 'Char.isSupplementaryCodePoint', 'Char.highSurrogate', 'Char.toCodePoint'
        
        The following holds:
        
        > isSupplementaryCodePoint x ==> (x == toCodePoint (highSurrogate x) (lowSurrogate x))
    -}
    pure native lowSurrogate  java.lang.Character.lowSurrogate   :: Int -> Char
    
    {--
        > Char.toCodePoint high low
        
        Converts the specified surrogate pair to its supplementary code point value. 
        This function does not validate the specified surrogate pair. 
        The caller must validate it using 'Char.isSurrogatePair' if necessary.
    -}
    pure native toCodePoint  java.lang.Character.toCodePoint :: Char -> Char -> Int
    
    {--
        Determines whether the specified pair of char values is a valid Unicode surrogate pair.
    -}
    pure native isSurrogatePair java.lang.Character.isSurrogatePair :: Char -> Char -> Bool
    
    {--
        Returns a value indicating a character's general category.
    -}
    pure native getType         java.lang.Character.getType         ∷ Char → Int 
                                                                    | Int  → Int

    {--
        Return the Unicode name of the code point or null if it is unassigned.
    -}
    pure native getName         java.lang.Character.getName         ∷ Char → Maybe String
                                                                    | Int  → Maybe String
    
{--
    'String' values are based on Java\'s @java.lang.String@ objects.
    'String' is an alias for 'StringJ' 'Char'
    -}
type String = StringJ Char
{--
    For technical reasons, the native string type is defined with a phantom type,
    which allows us to treat strings like character lists.
    
    The following rules apply:
    - There must be no polymorphic non empty string. Trying to extract elements from it
      with 'String.charAt' would fail with an exception at runtime.
    - Every function with return type ('StringJ' a) must either take one or more arguments
      of the same type which it manipulates, or it must return the empty string. In the former
      case, the elements of the result string must all be computed from the 
      elements of the argument strings.    
    -}    
protected data StringJ a = native java.lang.String {} where
    --- The length of a 'String'
    pure native length :: StringJ a -> Int
    {-- Like 'String.int', but the exception is not checked, thus only good when one *knows for sure* that the parse will succeed. -}
    pure native atoi java.lang.Integer.parseInt   :: String  -> Int
    {-- Like 'String.long', but the exception is not checked, thus only good when one *knows for sure* that the parse will succeed. -}
    pure native atol java.lang.Long.parseLong     :: String  -> Long
    {-- Like 'String.float', but the exception is not checked, thus only good when one *knows for sure* that the parse will succeed. -}
    pure native atof java.lang.Float.parseFloat   :: String  -> Float
    {-- Like 'String.double', but the exception is not checked, thus only good when one *knows for sure* that the parse will succeed. -}
    pure native atod java.lang.Double.parseDouble :: String  -> Double
    {-- Like 'String.integer', but the exception is not checked, thus only good when one *knows for sure* that the parse will succeed. -}
    pure  native aton new                          :: String  -> Integer
    {-- Safe way to parse an integer from a string.
        @java.lang.NumberFormatException@ will be caught and returned as 'Left' value.
        When the parse succeeds, the integer is returned in the 'Right' value.

        Use like this:
        > case s.int of
        >   Left exc -> ...     -- s is not well formed
        >   Right i  -> ...     -- the parsed value is in i
    -}
    pure  native int    java.lang.Integer.parseInt   :: String  -> (NumberFormatException|Int)
    --- Safe way to parse a long integer from a string. See 'String.int'
    pure  native long   java.lang.Long.parseLong     :: String  -> (NumberFormatException|Long)
    --- Safe way to parse a 'Float' value from a string. See 'String.int'
    pure  native float  java.lang.Float.parseFloat   :: String  -> (NumberFormatException|Float)
    --- Safe way to parse a 'Double' value from a string. See 'String.int'
    pure  native double java.lang.Double.parseDouble :: String  -> (NumberFormatException|Double)
    --- Safe way to parse a big 'Integer' value from a string. See 'String.int'
    pure  native integer new                         :: String  -> (NumberFormatException|Integer)
    --- retrieve character at index
    pure  native charAt :: String -> Int -> Char
    --- > str.indexOf ch
    --- the first index of _ch_ in _str_, or -1 if not present
    pure  native indexOf :: String -> Char -> Int
                          | String -> Char -> Int -> Int
                          | String -> String -> Int
                          | String -> String -> Int -> Int
    {-- Retrieve element of 'String' at index
    
        Because it is impossible to create a 'String' from anything but 'Char's,
        the type is not even wrong.
        
        Will be needed in the 'String' instance of 'frege.prelude.PreludeList#ListLike'
        that expects a type with kind @*->*@.
    -}
    pure  native polymorphicElemAt PreludeBase.polyCharAt{a} :: StringJ a -> Int -> a
    -- Get character at index.
    -- pure  native frozenGetAt  charAt :: String -> Int -> Char
    -- interpret this string as regex (unsafe, does not catch exceptions)
    -- see 'regcomp' for an alternative
    -- pure  native compile java.util.regex.Pattern.compile :: String -> Regex
    --- quote regular expression metacharacters in string
    pure  native quote   java.util.regex.Pattern.quote   :: String -> String
    --- quote replacement string metacharacters in string
    pure  native quoteReplacement   java.util.regex.Matcher.quoteReplacement
                            :: String -> String
    --- convert to lower case
    pure  native toLowerCase :: String -> String
    --- convert to upper case
    pure  native toUpperCase :: String -> String
    --- 'String.compareTo' is used in the 'Ord' instance of 'String'
    pure  native compareTo :: String -> String -> Int
    -- issue 251: type String enhancement
    pure  native compareToIgnoreCase :: String -> String -> Int
    --- Concatenate two strings, uses Java's @+@ operator
    pure  native ++ + :: StringJ a -> StringJ a -> StringJ a    -- String concatenation
    --- get the hash code
    pure  native hashCode :: String -> Int
    --- see 'substr'
    pure native substr     substring :: StringJ a -> Int -> Int -> StringJ a
    --- true if the second string is a prefix of the first one
    pure native startsWith           :: String -> String -> Bool
    --- convert an 'Int' to a 'String'
    pure native intToString java.lang.String.valueOf    :: Int -> String
    --- Format 1 to 9 values
    --- May throw @IllegalFormatException@, if the type of any argument does not fit the format specifier.
    pure native format java.lang.String.format {} 
        :: String -> a -> String
         | String -> a -> b -> String
         | String -> a -> b -> c -> String
         | String -> a -> b -> c -> d -> String
         | String -> a -> b -> c -> d -> e -> String
         | String -> a -> b -> c -> d -> e -> f -> String
         | String -> a -> b -> c -> d -> e -> f -> g -> String
         | String -> a -> b -> c -> d -> e -> f -> g -> h -> String
         | String -> a -> b -> c -> d -> e -> f -> g -> h -> i -> String

    pure native codePointAt         :: String -> Int -> Int
    pure native codePointBefore     :: String -> Int -> Int
    pure native codePointCount      :: String -> Int -> Int -> Int
    --- This is the native String.concat, just renamed because naming conflicts
    pure native concatenate concat  :: String -> String -> String
    pure native contains            :: String -> String -> Bool
    pure native contentEquals       :: String -> String -> Bool
    pure native isEmpty             :: String -> Bool
    pure native lastIndexOf         :: String -> Char -> Int
                                     | String -> Char -> Int -> Int
                                     | String -> String -> Int
                                     | String -> String -> Int -> Int    
    --pure native matches             :: String -> String -> Bool
    --pure native regionMatches       :: String -> Int -> String -> Int -> Int -> Bool
    --                                 | String -> Bool -> Int -> String -> Int -> Int -> Bool
    --- replace a character in a string
    pure native replace             :: String -> Char -> Char -> String
                                     -- String -> String -> String -> String 
    pure native trim                :: String -> String 

    --- wait on 'Object's monitor
    native wait frege.run.Concurrent.waitFor :: String -> IO () throws InterruptedException
    --- notify a single thread waiting on the objects monitor
    native notify frege.run.Concurrent.notifyOne :: String -> IO ()
    --- notify all threads waiting on the objects monitor
    native notifyAll frege.run.Concurrent.notifyAll :: String -> IO ()

{--
     @substr s start end@ returns the sub string of @s@ that starts
     with the character at position @start@
     and extends to the character at position @end-1@.

    This uses the native method @substring@ of class @java.lang.String@. It
    will throw an @IndexOutOfBoundsException@ if @start@ is negative or larger than
    @end@ or if @end@ is greater than the length of @s@.
 -}
pure native substr     substring :: StringJ a -> Int -> Int -> StringJ a
{--
    @strtail s n@ returns a new string that is a substring of string _s_.
    The substring begins with the character at the specified index
    and extends to the end of _s_.

    This uses the native method @substring@ of class @java.lang.String@. It
    will throw an @IndexOutOfBoundsException@ if _n_ is negative or larger than
    the length of _s_.
-}
pure native strtail        substring :: StringJ a -> Int -> StringJ a


atoi (s::String) = s.atoi


--- 'Float' values are based on Java's primitive @float@ values.
{--
    According to the Java Language Specification §4.2.3, @float@ values are
    32-bit-precision binary floating point values. The values and the operations
    on it behave as specified in the IEEE Standard for Binary Floating-Point Arithmetic.
-}
data Float = native float where
    {--
      Returns the closest 'Int' value to the argument.
      The result is rounded to an integer by adding 1/2,
      taking the 'frege.prelude.Math#floor' of the result,
      and casting the result to type int.

      The following property holds:

      > (f < Int.maxBound.float && f > Int.minBound.float) ==>
      >   (f.int.float == (f + 0.5f).floor)

      Special cases:
      - If the argument is NaN, the result is 0.
      - If the argument is negative infinity or any value less than or equal
      to the value of 'Int.minBound', the result is equal to the value of
      'Int.minBound'.
      - If the argument is positive infinity or any value greater than or equal
      to the value of 'Int.maxBound', the result is equal to the value of
      'Int.maxBound'.
    -}
    pure  native int    java.lang.Math.round :: Float -> Int
    
    --- Applies the java widening primitive conversion from @float@ to @double@.
    pure  native double "(double)"           :: Float -> Double
    
    --- bit representation of a float serves as hashCode
    pure native hashCode java.lang.Float.floatToIntBits :: Float -> Int
    
    --- positive infinity
    pure native positiveInfinity  "java.lang.Float.POSITIVE_INFINITY" :: Float

    --- negative infinity
    pure native negativeInfinity  "java.lang.Float.NEGATIVE_INFINITY" :: Float

    --- the NaN value provided by the Java runtime
    pure native nan               "java.lang.Float.NaN" :: Float


--- 'Double' values are Java's primitive @double@ values.
{--
    According to the Java Language Specification §4.2.3, @double@ values are
    64-bit-precision binary floating point values. The values and the operations
    on it behave as specified in the IEEE Standard for Binary Floating-Point Arithmetic.
    -}
data Double = native double where
    {--
      Returns the closest 'Long' value to the argument.
      The result is rounded to an integer by adding 1/2,
      taking the 'frege.prelude.Math#floor' of the result,
      and casting the result to type @long@.

      The following property holds:

      > (d < Long.maxBound.double && d > Long.minBound.double) ==>
      >   (d.long.double == (d + 0.5d).floor)

      Special cases:
      - If the argument is NaN, the result is 0.
      - If the argument is negative infinity or any value less than or equal
      to the value of 'Long.minBound', the result is equal to the value of
      'Long.minBound'.
      - If the argument is positive infinity or any value greater than or equal
      to the value of 'Long.maxBound', the result is equal to the value of
      'Long.maxBound'.
     -}
    pure  native long   java.lang.Math.round :: Double -> Long
        
    --- Applies the java narrowing primitive conversion from @double@ to @float@
    pure  native float  "(float)"            :: Double -> Float
    
    --- bit representation of a double
    pure native longBits java.lang.Double.doubleToLongBits :: Double -> Long
    --- the 'hashCode' is that of the 'Long' value used to represent the 'Double'
    hashCode d = (longBits d).hashCode

    --- positive infinity
    pure native positiveInfinity  "java.lang.Double.POSITIVE_INFINITY" :: Double

    --- negative infinity
    pure native negativeInfinity  "java.lang.Double.NEGATIVE_INFINITY" :: Double

    --- the NaN value provided by the Java runtime
    pure native nan               "java.lang.Double.NaN" :: Double


{--
    The Java Object type
    -}
protected data Object = pure native java.lang.Object where
    --- for any value, we can get its @Java@ class
    pure native getClass  frege.runtime.Runtime.getClass {a} ::  a -> Class a
    --- wait on 'Object's monitor
    native wait frege.run.Concurrent.waitFor :: Object -> IO () throws
        InterruptedException
    --- notify a single thread waiting on the objects monitor
    native notify frege.run.Concurrent.notifyOne :: Object -> IO ()
    --- notify all threads waiting on the objects monitor
    native notifyAll frege.run.Concurrent.notifyAll :: Object -> IO ()
    
protected data InterruptedException = pure native java.lang.InterruptedException

{-- warning: probably catches more exceptions than you want to handle, use (Exception1|Exception2|Result)
    This is the principal return type for java methods that are expected to
    throw exceptions.
    
    It is strongly recommended to use more specific exception types.
 -}
type CatchAll  = Either Throwable


{--
 * We need to do some reflection from frege code.
 * For example, when we catch a 'Throwable' thrown from Java code.
 * we might want to know what it is.
 -}
data Class a = pure native java.lang.Class where
    pure  native getName    :: Class a -> String
    native       forName java.lang.Class.forName{}  -- returns Class<?> !!! 
                            :: String -> IO (ClassNotFoundException|Class a)


--- Frege wrapper for java Throwables.
protected data Throwable = pure native java.lang.Throwable where
    pure native getLocalizedMessage :: Throwable -> String
    pure native getMessage ::          Throwable -> String
    native      printStackTrace ::     Throwable -> IO ()
    
    --- give the class name of this exception
    caught :: Throwable -> String
    caught t = t.getClass.getName



{--
 * Used to construct a strict tuple. Don't use anymore!
 -}
pure native strictTuple2  PreludeBase.TTuple2.mk {} :: a -> b -> (a,b);
--- Constructs a strict 3-tuple. See remarks for 'strictTuple2'.
pure native strictTuple3  PreludeBase.TTuple3.mk {} :: a -> b -> c -> (a,b,c);
--- Constructs a strict 4-tuple. See remarks for 'strictTuple2'.
pure native strictTuple4  PreludeBase.TTuple4.mk {} :: a -> b -> c -> d -> (a,b,c,d);
--- Constructs a strict 5-tuple. See remarks for 'strictTuple2'.
pure native strictTuple5  PreludeBase.TTuple5.mk {} :: a -> b -> c -> d -> e -> (a,b,c,d,e);
--- Constructs a strict 6-tuple. See remarks for 'strictTuple2'.
pure native strictTuple6  PreludeBase.TTuple6.mk {} :: a -> b -> c -> d -> e -> f -> (a,b,c,d,e,f);
--- Constructs a strict 7-tuple. See remarks for 'strictTuple2'.
pure native strictTuple7  PreludeBase.TTuple7.mk {} :: a -> b -> c -> d -> e -> f -> g -> (a,b,c,d,e,f,g);
--- Constructs a strict 8-tuple. See remarks for 'strictTuple2'.
pure native strictTuple8  PreludeBase.TTuple8.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> (a,b,c,d,e,f,g,h);
--- Constructs a strict 9-tuple. See remarks for 'strictTuple2'.
pure native strictTuple9  PreludeBase.TTuple9.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> (a,b,c,d,e,f,g,h,i);
--- Constructs a strict 10-tuple. See remarks for 'strictTuple2'.
pure native strictTuple10 PreludeBase.TTuple10.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> (a,b,c,d,e,f,g,h,i,j);
--- Constructs a strict 11-tuple. See remarks for 'strictTuple2'.
pure native strictTuple11 PreludeBase.TTuple11.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> (a,b,c,d,e,f,g,h,i,j,k);
--- Constructs a strict 12-tuple. See remarks for 'strictTuple2'.
pure native strictTuple12 PreludeBase.TTuple12.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> (a,b,c,d,e,f,g,h,i,j,k,l);
--- Constructs a strict 13-tuple. See remarks for 'strictTuple2'.
pure native strictTuple13 PreludeBase.TTuple13.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> (a,b,c,d,e,f,g,h,i,j,k,l,m);
--- Constructs a strict 14-tuple. See remarks for 'strictTuple2'.
pure native strictTuple14 PreludeBase.TTuple14.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n);
--- Constructs a strict 15-tuple. See remarks for 'strictTuple2'.
pure native strictTuple15 PreludeBase.TTuple15.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o);
--- Constructs a strict 16-tuple. See remarks for 'strictTuple2'.
pure native strictTuple16 PreludeBase.TTuple16.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p);
--- Constructs a strict 17-tuple. See remarks for 'strictTuple2'.
pure native strictTuple17 PreludeBase.TTuple17.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q);
--- Constructs a strict 18-tuple. See remarks for 'strictTuple2'.
pure native strictTuple18 PreludeBase.TTuple18.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r);
--- Constructs a strict 19-tuple. See remarks for 'strictTuple2'.
pure native strictTuple19 PreludeBase.TTuple19.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s);
--- Constructs a strict 20-tuple. See remarks for 'strictTuple2'.
pure native strictTuple20 PreludeBase.TTuple20.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t);
--- Constructs a strict 21-tuple. See remarks for 'strictTuple2'.
pure native strictTuple21 PreludeBase.TTuple21.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> u -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u);
--- Constructs a strict 22-tuple. See remarks for 'strictTuple2'.
pure native strictTuple22 PreludeBase.TTuple22.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> u -> v -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v);
--- Constructs a strict 23-tuple. See remarks for 'strictTuple2'.
pure native strictTuple23 PreludeBase.TTuple23.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> u -> v -> w -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w);
--- Constructs a strict 24-tuple. See remarks for 'strictTuple2'.
pure native strictTuple24 PreludeBase.TTuple24.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> u -> v -> w -> x -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x);
--- Constructs a strict 25-tuple. See remarks for 'strictTuple2'.
pure native strictTuple25 PreludeBase.TTuple25.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> u -> v -> w -> x -> y -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y);
--- Constructs a strict 26-tuple. See remarks for 'strictTuple2'.
pure native strictTuple26 PreludeBase.TTuple26.mk {} :: a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> k -> l -> m -> n -> o -> p -> q -> r -> s -> t -> u -> v -> w -> x -> y -> z -> (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z);




--- @a `seq` b@ evaluates _a_ before it returns _b_
--- This is a right associative operator with precedence 15.
seq !a b = b

--######### undefined things ####################
--- An unchecked subclass of @java.lang.RuntimeException@ for the Frege Runtime
--- An instance of 'Undefined' will be thrown if 'undefined' or ('error' msg) is evaluated.  
data Undefined = pure native frege.runtime.Undefined where
    {-- 
        create an 'Undefined' value with a message ('String')
        or with a message and a cause. The cause is another
        exception that caused this one.
        -} 
    pure  native new :: String -> Undefined
                      | String -> Throwable -> Undefined
     
    {-- create an 'Undefined' value from a cause ('Throwable'). 
        The message will be taken from the cause.
         -}
    newX :: Throwable -> Undefined
    newX jex = new ((("caused by ". ++ jex.getClass.getName). ++ ": "). ++ jex.getMessage) jex
    
    --- Throw this 'Undefined', this will abort the computation evaluating it.
    --- Actually, the return type is not correct, since it never returns.
    pure native die  :: Undefined -> Bool

--- A subclass of 'Undefined', used by the runtime to signal failed pattern matches
data NoMatch     = pure native frege.runtime.NoMatch

--- A subclass of 'Undefined', used by the runtime to signal failed guards
data GuardFailed = pure native frege.runtime.GuardFailed

--- @java.lang.NumberFormatException@ needed for string conversion operations
--- declared *@protected@* to avoid name conflicts with 'frege.java.Lang#NumberFormatException' 
protected data NumberFormatException = pure native java.lang.NumberFormatException where
    {-- 
        create an 'NumberFormatException' value with a message ('String')
        or with a message and a cause. The cause is another
        exception that caused this one.
        -} 
    pure  native new :: String -> NumberFormatException
                      | String -> Throwable -> NumberFormatException

--- Forward declaration of 'frege.java.Lang#ClassNotFoundException'
protected data ClassNotFoundException 
    = pure native java.lang.ClassNotFoundException

--- This is the standard undefined value.
undefined :: u
undefined = error "undefined"

--- nowarn: application of error will diverge
--- Construct an undefined value with an informative message.
--- When evaluated, an 'Undefined' exception will be thrown.
error :: String -> u
error s   = if (Undefined.new s :: Undefined).die then error "a" else error "b"

--- nowarn: diverge
--- Constructs an undefined value from a java exception and throws it.
throw u   = if (Undefined.newX u).die then undefined else undefined


--######### boolean expr ########################
--- The Java @!@ operator on booleans
pure  native !   ∷ Bool → Bool      --  = if b then false else true;
--- complement
pure  native ? ~ ∷ Int → Int

{-- The Java @&&@ operator on booleans. Note that since this is a
    native function, the second argument appears strict to the compiler
    when in fact it is lazy at the Java level.
    This can lead to inconsistent results in some cases. For example, the following
    program correctly prints @false@ in the first line of the output, but then aborts:
    > main _ = do
    >    stdout << (false && undefined) << "\n"
    >    stdout << conj false undefined << "\n"
    >  where
    >    conj a b = a && b

    Note that the very same behaviour is seen in the following java program

    > public class And {
    >    static boolean undef() {
    >        if (true) throw new Error("undefined");
    >        return false;
    >    }
    >    static boolean conj(boolean a, boolean b) { return a&&b; }
    >    public static void main(String[] args) {
    >        System.out.println(false && undef());
    >        System.out.println(conj(false, undef()));
    >    }
    > }

    One could thus say that '&&' behaves exactly like the Java operator including
    the fact that it cannot be replaced by a function without changing the semantics
    of a program.

    For an alternative see 'und'
    -}
pure  native && :: Bool -> Bool -> Bool

{-- 
    The Java @||@ operator on booleans.
    
    Note that since this is a
    native function, the second argument appears strict to the compiler
    when in fact it is lazy at the Java level.
    
    This can lead to inconsistent results in cases where the wrong strictness of
    the second argument propagates to arguments of the function that contains 
    an application of '||'. (The documentation for '&&' has an example.)
    
    See 'oder' for an alternative
    -}
pure native || :: Bool -> Bool -> Bool

{-- Like '&&', but second argument is lazy.
    The @`und`@ operator has the same precedence and arity as '&&'.
    The definition is
    > a `und` b = if a then b     else false
    This should really be named _and_, but Haskell 2010 uses this already for lists.
    Hence we use the german word _und_.
    -}
a `und` b = if a then b     else false

{-- Like '||', but second argument is lazy.
    The @`oder`@ operator has the same precedence and arity as '||'.
    The definition is
    > a `oder`  b = if a then true  else b
    This should really be named _or_, but Haskell 2010 uses this already for lists.
    Hence we use the german word _oder_.
    -}
a `oder`  b = if a then true  else b

{--
    @not b@ is true if _b_ is false, otherwise true. Uses java's '!' operator.
 -}
pure  native not "!" :: Bool -> Bool

{--
 * @a ^^ b@ is true if either _a_ or _b_ is true, but not both.
 * > a ^^ b = if a then not b else b
 -}
a ^^ b = if a then not b else b

--######### expr identity ######################
{-- This checks for object identity or equality of primitive values
    using Java's @==@ operator.
    It evaluates its arguments, so undefined values cannot be compared. -}
pure  native === == :: a -> a -> Bool;
{-- This checks for object identity or inequality of primitive values
    using Java's @!=@ operator.
    It evaluates its arguments, so undefined values cannot be compared. -}
pure  native !== != :: a -> a -> Bool;


--########### class Ord - compare ordered things ##################
--- 'Ordering' encodes the results of comparisons, see also  '<=>'
data Ordering = Lt | Eq | Gt

{--
  The 'Ord' class provides relational operators as well as the functions 'max' and 'min'.
  The default implementation defines them all in terms of the _compare_ operator '<=>'.

  Making some type an instance of 'Ord' makes it automatically an instance of 'Eq' if it
  is not one already and if it has an implementation for 'hashCode'. 
  The operators '==' and '!=' will be defined in terms of '<=>'.

  Instances of 'Ord' can be derived automatically for algebraic data types when
  all elements of the type are themselves instances of 'Ord' and when the type is
  an instance of 'Eq'.
 -}
class Eq o => Ord o where
    {-- This operator must be defined in all instances. It compares its operands and
        returns 'Lt' if the first is lower than the second, 'Gt' if the first is
        greater than the second and 'Ordering.Eq' otherwise.

        The following shall be invariantly true:
        > case a <=> b of { Eq -> a == b; _ -> a != b }

        -}
    (<=>) :: o -> o -> Ordering      -- must be defined
    compare :: o -> o -> Ordering

    {-- Relational @<@ operator. Obeys the following laws:
        > if a < b && b < c then a < c
        > a < b == b > a
        -}
    (<)   :: o -> o -> Bool
    {-- Relational @<=@ operator. Obeys the following laws:
        > if a <= b && b <= c then a <= c
        > a <= b == b >= a
        > a <= b == !(a > b)
        -}
    (<=)  :: o -> o -> Bool
    {-- Relational @>@ operator. Obeys the following laws:
        > if a > b && b > c then a > c
        > a > b == b < a
        -}
    (>)   :: o -> o -> Bool
    {-- Relational @>=@ operator. Obeys the following laws:
        > if a >= b && b >= c then a >= c
        > a >= b == b <= a
        > a >= b == !(a < b)
        -}
    (>=)  :: o -> o -> Bool
    --- > max a b = if a > b then a else b
    max   :: o -> o -> o
    --- > min a b = if a < b then a else b
    min   :: o -> o -> o
    (a) < (b)   = case a <=> b of { Lt -> true;   _ -> false; }
    (a) <= (b)  = case a <=> b of { Gt -> false;  _ -> true;  }
    (a) >= (b)  = case a <=> b of { Lt -> false;  _ -> true;  }
    (a) > (b)   = case a <=> b of { Gt -> true;   _ -> false; }
    max a b = if a > b then a else b
    min a b = if a < b then a else b
    -- provided for Haskell compatibility as alias for '<=>'
    compare = (<=>)
    {-- This implementation for the ('==') operator is being used in instances
        of 'Ord' when the instantiated type is not already an instance of 'Eq'.
    -}
    (a) == (b)  = case a <=> b of { Eq -> true;   _ -> false; }
    {-- This implementation for the ('!=') operator is being used in instances
        of 'Ord' when the instantiated type is not already an instance of 'Eq'.
    -}
    (a) != (b)  = case a <=> b of { Eq -> false;  _ -> true;  }

--############# class Enum ############################################
{--
 * Class 'Enum' defines operations on sequentially ordered types.
 *
 * A type that is an instance of 'Enum' is also an instance
 * of 'Ord' (and, in turn, of 'Eq').
 *
 * Instances of 'Enum' may be derived for any enumeration type
 * (types whose constructors have no fields).
 * If there is no 'hashCode' provided, it will be the same as 'ord'.
 *
 * Enumeration types have special syntactic support with the range list:
 > [a .. b]
 > [a ..]
 > [a,b .. c]
 > [a,b ..]
 -}
class Ord e => Enum e where
    {-- @ord e@ returns the ordinal number associated with the value @e@. For
     * enumeration types, 'ord' is the same as 'constructor', for 'Int', it is the
     * identity function.
     * Some types, like 'Long', cannot map all their values to 'Int', in such cases
     * the result of applying 'ord' may be meaningless.
     -}
    ord :: e -> Int
    {--
     * This is the default implementation of the compare operator,
     * that makes each 'Enum' type an 'Ord' type automatically.
     * > a <=> b  =  (ord a).<=>  (ord b)
     -}
    a <=> b = (ord a). <=> (ord b)
    {--
     * @T.from i@ maps the 'Int' value @i@ to a value of @T@, such that
     >   ord (T.from i) == i
     * unless there is no value @e@ of @T@ so that @ord e == i@. In the
     * latter case, the result is 'undefined'.
     -}
    from :: Int -> e
    --- @succ e@ is the successor of @e@ or 'undefined' if there is no such successor.
    succ :: e -> e
    --- @pred e@ is the predecessor of @e@ or 'undefined' if there is no predecessor.
    pred :: e -> e
    -- pred x = from (ord x - 1)
    -- succ x = from (ord x + 1)
    {- @a .. b@ is the list @[a, succ a, succ (succ a), ..., b ]@
     * if @a < b@, or [a] if @a == b@ or the empty list if @a > b@.
     
    (..) :: e -> e -> [e]
    (a) .. (b)
        | a < b     = a:(succ a). .. b
        | a == b    = [a]
        | otherwise = []    -}
    --- default implementation for 'Eq.hashCode' is same as 'ord'
    hashCode = ord
    --- used in translating @[n,n'..m]
    enumFromThenTo :: e -> e -> e -> [e]
    --- used in translating @[n,n'..]
    enumFromThen :: e -> e -> [e]
    --- used in translating @[n..m]
    enumFromTo :: e -> e -> [e]
    enumFromTo a b
        | a < b     = a:enumFromTo (succ a) b
        | a == b    = [a]
        | otherwise = []
    --- used in translating @[n..]
    enumFrom :: e -> [e]
    enumFrom a = enumFromThen a (succ a)

  
instance Eq () where
    () != () = false
    () == () = true
    hashCode () = 42


--########### class Num - basic arithmetic ########################
{-- The 'Num' class provides the operators ('+'), ('-') and ('*') as well as
    some functions that are common for all numeric types.
    -}
class Ord n => Num n where
    --- Computes the sum of two numbers
    (+) :: n -> n -> n
    --- Computes the difference of two numbers
    (-) :: n -> n -> n
    --- use @(subtract a)@ instead of @\\b -> b-a@ in sections
    subtract :: n -> n -> n
    --- Computes the product of two numbers
    (*) :: n -> n -> n
    --- Computes the absolute value
    abs :: n -> n
    --- Negates a number n such that if n is a number
    --- > n + negate n == 0
    negate :: n -> n
    --- @sign n@ is -1 if n<0, 1 if n>0 and 0 otherwise
    sign :: n -> Int
    --- the number 1 in the instantiated type
    one  :: n
    --- the number 0 in the instantiated type
    zero :: n
    abs n = if n < zero then zero-n else n
    negate n =  zero-n
    subtract b a = a-b
    sign n = constructor (n <=> zero) - 1
    --- converts an 'Int' value to the instantiated type
    fromInt :: Int -> n
    --- converts an 'Integer' value to the instantiated type
    fromInteger :: Integer -> n
    {-- Floating point number types may have special values for _infinity_
        and _negative infinity_. @isFinite n@ yields @true@ if @n@ is an infinite
        value and @false@ in all other cases.

        The default implementation always returns @false@ so that implementors of
        instances for types without special values for infinity need not care.

        See also 'isNumber'.
    -}
    isInfinite :: n -> Bool
    isInfinite _ = false
    {-- Floating point number types may have a special values for
        _not a number_ (NaN). For example, @0d / 0d@ is NaN.
        @isNaN n@ yields @true@ if @n@ is the special value that indicates that
        @n@ is not a number and @false@ in all other cases.

        The default implementation always returns @false@ so that implementors of
        instances for types without such a special values need not care.

        See also 'isNumber'.
    -}
    isNaN :: n -> Bool
    isNaN _ = false
    {-- Returns @true@ if @n@ is neither infinite (see 'isInfinite') nor NaN (see 'isNaN').

        Note that certain properties for functions on numbers are true only under the assumption
        that the argument values are numbers.

        The default implementation is
        > isNumber n = !(isInfinite n) && !(isNaN n)
        so that the function should always compute
        the right answer as long as 'isInfinite' and 'isNaN' do.
    -}
    isNumber :: n -> Bool
    isNumber n = !(isInfinite n) && !(isNaN n)


{--
 * The 'Real' class provides the division operator ('/').
 -}
class Num r => Real r where
    --- the division operator
    (/) :: r -> r -> r
    --- convert a 'Double' to any 'Real' value
    fromDouble :: Double -> r
    --- positive infinity, negative infinity and not a number
    positiveInfinity, negativeInfinity, nan :: r





{--
 * 'Integer' is an instance of 'Ord'
 -}
instance Ord Integer where
    a <=> b = (a.compareTo b). <=> 0
    a >   b = (a.compareTo b). >   0
    a <   b = (a.compareTo b). <   0
    a >=  b = (a.compareTo b). >=  0
    a <=  b = (a.compareTo b). <=  0
    a ==  b = (a.compareTo b). ==  0
    a !=  b = (a.compareTo b). !=  0

{--
 * 'Integer' is an instance of 'Enum'
 -}
instance Enum Integer where
    --- @succ b@  is the same as @b + 1.big@
    succ b = b + Integer.one
    --- @succ b@  is the same as @b + 1.big@
    pred b = b - Integer.one
    --- @ord b@ is only defined if the value of b is in the range 'Int.minBound' .. 'Int.maxBound'
    ord b  = b.int
    --- @Integer.from i@ is the same as @Int.big i@
    from i = i.big
    enumFromTo a b
        | a < b     = a:enumFromTo (succ a) b
        | a == b    = [a]
        | otherwise = []
    enumFrom !a        = a : enumFrom (succ a)
    enumFromThen !a !b = goFromBy a (b-a)
        where
            goFromBy :: Integer -> Integer -> [Integer]
            goFromBy !a !inc = a : goFromBy (a+inc) inc
    enumFromThenTo !a !b c = if a<b && a<=c || a>b && a>=c
                                then goFromByTo a (b-a) c
                                else []
        where
            goFromByTo !a inc c
                | inc > 0n, a < c, (c-a) < inc = [a]
                | a == c                       = [a]
                | inc < 0n, a > c, (c-a) > inc = [a]
                | otherwise                    = a : goFromByTo (a+inc) inc c  


{--
 * 'Integer' is an instance of 'Integral'
 -}
instance Integral Integer where
    fromInt i = Int.big i
    fromInteger b = b           -- identity
    big b     = b               -- i am already big
    even n = (n Integer.`.&.` one) == zero
    odd  n = (n Integer.`.&.` one) != zero


toInteger = Integral.big

--- Class 'Integral' provides division and remainder operations for integral numbers.
class Num i => Integral i where
    --- integer division
    div, quot :: i -> i -> i
    --- Haskell compatibility
    quotRem, divMod :: i -> i -> (i, i)
    quotRem a b = (a `quot` b, a `rem` b)
    divMod  a b = (a `div` b,  a `mod` b)
    --- The remainder á la Java operator @%@ - @a `rem` b@ has same sign as @a@
    --- > forAll arbitrary (\a -> forAll arbitrary (\b -> (a `quot` b) * b + (a `rem` b) = a
    --- This behaviour is the same as in Haskell
    rem :: i -> i -> i
    mod :: i -> i -> i
    --- This modulo operator works so that
    --- > forAll arbitrary (\a -> forAll arbitrary (\b -> (a `div` b) * b + (a `mod` b) = a))
    --- In addition, it is the case that
    --- > forAll arbitrary (\a -> forAll arbitrary (\b -> @(a `quot` b) == (a `div` b) || (a `quot` b) == (a `div` b)-1))
    a `mod` b  = case a `rem` b of
                    r | r == zero                  = r
                      | (a >= zero) == (b >= zero) = r              -- a and b have same sign
                      | otherwise                  = r + b
    a `div` b  = case a `quot` b of
                    q | (a >= zero) == (b >= zero) = q              -- a and b have same sign
                      | q * b       == a           = q
                      | otherwise                  = q-one

    --- every integral number can be converted to a big 'Integer'
    big :: i -> Integer
    
    --- every 'Num' can be made from an 'Integral'
    fromIntegral :: Num b => i -> b
    fromIntegral i = fromInteger (big i)
    
    -- -----------------------------------------------------
    {--
        'gcd' @x y@ is the non-negative factor of both @x@ and @y@ of which
        every common factor of @x@ and @y@ is also a factor; for example
        'gcd' @4 2 = 2@, @'gcd' (-4) 6 = 2@, @'gcd' 0 4@ = @4@. @'gcd' 0 0@ = @0@.
        (That is, the common divisor that is \"greatest\" in the divisibility
        preordering.)
    
        Note: Since for signed fixed-width integer types, 'abs' 'minBound' < @0@,
        the result may be negative if one of the arguments is 'minBound' (and
        necessarily is if the other is @0@ or 'minBound') for such types.
        -}
    gcd, gcdHelper :: i -> i -> i
    gcd x y         =  gcdHelper (abs x) (abs y)
    
    --- 'lcm' @x y@ is the smallest positive integer that both @x@ and @y@ divide.
    lcm             :: i -> i -> i
    lcm x y
        | x == zero || y == zero = zero
        | otherwise              =  abs ((x `quot` (gcd x y)) * y)

    --- @ x ^ n @  raise _x_ to the _n_-th power
    --- The exponent must be positive. 
    (^) :: Num a => a -> i -> a
    !x0 ^ !y0 
        | y0 < 0    = error "Negative exponent"
        | y0 == 0   = 1
        | otherwise = powf x0 y0
    
    even, odd :: i -> Bool

    --- helper for 'Integral.^'
    private powf :: Num a => a -> i -> a
    private powf !x !y 
        | even y    = powf (x * x) (y `quot` 2)
        | y == 1    = x
        | otherwise = powg (x * x) ((y - 1) `quot` 2) x
    --- helper for 'Integral.^'
    private powg :: Num a => a -> i -> a -> a
    private powg !x !y !z 
        | even y = powg (x * x) (y `quot` 2) z
        | y == 1 = x * z
        | otherwise = powg (x * x) ((y - 1) `quot` 2) (x * z)

    --- worker function for 'Integral.gcd', needs not pollute the namespace
    private gcdHelper !a !b 
        | b == zero = a
        | otherwise = gcdHelper b (a `rem` b)


--############ Int instances & functions ############################

instance Eq Int where
    --- Uses the java @==@ operator for comparison of 'Int' values.
    pure native ==     :: Int -> Int -> Bool
    --- Uses the java @!=@ operator for comparison of 'Int' values.
    pure native !=     :: Int -> Int -> Bool


instance Ord Int where
    --- Uses the java @<=@ operator for comparison of 'Int' values.
    pure native <=     :: Int -> Int -> Bool
    --- Uses the java @>=@ operator for comparison of 'Int' values.
    pure native >=     :: Int -> Int -> Bool
    --- Uses the java @<@ operator for comparison of 'Int' values.
    pure native <      :: Int -> Int -> Bool
    --- Uses the java @>@ operator for comparison of 'Int' values.
    pure native >      :: Int -> Int -> Bool
    (<=>) :: Int -> Int -> Ordering
    (a) <=> (b) = if a<b then Lt else if a>b then Gt else Eq


instance Num Int where
    --- Uses the java @+@ operator to add 2 'Int' values.
    pure native +  :: Int -> Int -> Int
    --- Uses the java @\*@ operator to multiply 2 'Int' values.
    pure native *  :: Int -> Int -> Int
    --- Uses the java @-@ operator to subtract one 'Int' value from another.
    pure native -  :: Int -> Int -> Int
    --- the integer constant 0
    zero = 0
    --- the integer constant 1
    one = 1
    {-- Returns the negated argument if it is negative, otherwise the argument itself.

        This does not work for 'Int.minBound' since there is no corresponding positive
        value that can be represented as an 'Int'. Rather
        > abs Int.minBound == Int.minBound
    -}
    abs i = if i < 0 then  negate i else i
    {-- @negate i@ computes @0-i@ using the java negation operator @-@.

        This does not work for 'Int.minBound' since there is no corresponding positive
        value that can be represented as an 'Int'. Rather
        > negate Int.minBound == Int.minBound
    -}
    pure native negate "-" :: Int -> Int
    --- For 'Int' values, this is the identity function.
    fromInt i = i
    fromInteger b = b.int


instance Eq Long where
    --- Uses the java @==@ operator for comparison of 'Long' values.
    pure native ==     :: Long -> Long -> Bool
    --- Uses the java @!=@ operator for comparison of 'Long' values.
    pure native !=     :: Long -> Long -> Bool


instance Ord Long where
    --- Uses the java @<=@ operator for comparison of 'Long' values.
    pure native <=     :: Long -> Long -> Bool
    --- Uses the java @>=@ operator for comparison of 'Long' values.
    pure native >=     :: Long -> Long -> Bool
    --- Uses the java @<@ operator for comparison of 'Long' values.
    pure native <      :: Long -> Long -> Bool
    --- Uses the java @>@ operator for comparison of 'Long' values.
    pure native >      :: Long -> Long -> Bool
    (<=>) :: Long -> Long -> Ordering
    (a) <=> (b) = if a<b then Lt else if a>b then Gt else Eq


instance Num Long where
    --- Uses the java @+@ operator to add two 'Long' values.
    pure native +  :: Long -> Long -> Long
    --- Uses the java @\*@ operator to multiply two 'Long' values.
    pure native *  :: Long -> Long -> Long
    --- Uses the java @-@ operator to subtract a 'Long' value from another.
    pure native -  :: Long -> Long -> Long
    --- The constant @0L@.
    zero = 0L
    --- The constant @1L@.
    one  = 1L
    {-- Returns the negated argument if it is negative, otherwise the argument itself.

        This does not work for 'Long.minBound' since there is no corresponding positive
        value that can be represented as a 'Long'. Rather
        > abs Long.minBound == Long.minBound
    -}
    abs i = if i < 0L then 0L-i else i
    {-- @negate a@ computes @0L-a@ using the java negation operator @-@.

        This does not work for 'Long.minBound' since there is no corresponding positive
        value that can be represented as a 'Long'. Rather
        > negate Long.minBound == Long.minBound
    -}
    pure native negate "-" :: Long -> Long
    --- applies the widening primitive conversion (JLS §5.1.2) from @int@ to @long@
    fromInt i = i.long
    fromInteger n = n.long





{--
 * A class for data types that have a lower and an upper bound.
 *
 * Instances of 'Bounded' can be derived automatically for enumeration types.
 -}
class Bounded b where
    --- the lower bound
    minBound :: b
    --- the upper bound
    maxBound :: b


instance Bounded Int where
    --- the smallest 'Int' value  -2147483648 (or -(2**31))
    minBound  = 0x80000000
    --- the largest 'Int' value  2147483647 (or (2**31)-1)
    maxBound  = 0x7fffffff



instance Enum Int where

    --- > ord i = i
    ord  (i::Int) = i
    --- > from i = i
    from (i::Int) = i
    --- @pred i@ is the same as @i-1@ except for @pred Int.minBound@, which is 'undefined'
    pred i
        | i > Int.minBound = i-1
        | otherwise = error "pred Int.minBound"

    --- @succ i@ is the same as @i+1@ except for @succ Int.maxBound@, which is 'undefined'
    succ i
        | i < Int.maxBound = i+1
        | otherwise = error "succ Int.maxBound"
    enumFromTo a b
        | a < b     = a:enumFromTo (succ a) b
        | a == b    = [a]
        | otherwise = []
    enumFrom a       = enumFromTo a maxBound
    enumFromThen !a !b = enumFromThenTo a b (if a<b then maxBound else minBound)
    enumFromThenTo !a !b c = if a<b && a<=c || a>b && a>=c
                                then goFromByTo a (b-a) c
                                else []
        where
            goFromByTo !a inc c
                | inc > 0, a < c, (c-a) < inc = [a]
                | a == c                      = [a]
                | inc < 0, a > c, (c-a) > inc = [a]
                | otherwise                   = a : goFromByTo (a+inc) inc c  
        


instance Bounded Long where
    --- the smallest 'Long' value  -9223372036854775808 (or -(2**63))
    minBound  = 0x8000000000000000L
    --- the largest 'Long' value  9223372036854775807 (or (2**63)-1)
    maxBound  = 0x7fffffffffffffffL

instance Enum Long where

    --- @ord l@ is only valid if @Int.minBound.long <= l && l <= Int.maxBound@
    ord  (i::Long) = i.int;

    --- @Long.from i@ returns a 'Long' with the same numeric value as @i@.
    from (i::Int)  = i.long;

    --- @pred a@ is the same as @a-1L@ except for @pred Long.minBound@, which is 'undefined'
    pred i
        | i > Long.minBound = i-1L
        | otherwise = error "pred Long.minBound"

    --- @succ a@ is the same as @a+1L@ except for @succ Long.maxBound@, which is 'undefined'
    succ i
        | i < Long.maxBound = i+1L
        | otherwise = error "succ Long.maxBound"
    enumFromTo a b
        | a < b     = a:enumFromTo (succ a) b
        | a == b    = [a]
        | otherwise = []
    enumFrom a       = enumFromTo a maxBound
    enumFromThen !a !b = enumFromThenTo a b (if a<b then maxBound else minBound)
    enumFromThenTo !a !b c = if a<b && a<=c || a>b && a>=c
                                then goFromByTo a (b-a) c
                                else []
        where
            goFromByTo !a inc c
                | inc > 0L, a < c, (c-a) < inc = [a]
                | a == c                      = [a]
                | inc < 0L, a > c, (c-a) > inc = [a]
                | otherwise                   = a : goFromByTo (a+inc) inc c  




instance Integral Int where
    pure native rem  %    :: Int -> Int -> Int
    pure native quot /    :: Int -> Int -> Int

    even n = (n Int.`.&.` one) == zero
    odd  n = (n Int.`.&.` one) != zero

    big l = Integer.valueOf l.long


instance Integral Long where
    pure native rem %      :: Long -> Long -> Long
    pure native quot /     :: Long -> Long -> Long
    even n = (n Long.`.&.` one) == zero
    odd  n = (n Long.`.&.` one) != zero
    big l = Integer.valueOf l


--############# Bool instances ########################################


instance Ord Bool where
    false <  true   = true
    _     <  _      = false
    true  >  false  = true
    _     >  _      = false
    false <= _      = true
    true  <= b      = b
    false >= b      = !b
    true  >= _      = true
    true  <=> false = Gt
    false <=> true  = Lt
    _     <=> _     = Eq


instance Bounded Bool where
    minBound   = false
    maxBound   = true

instance Enum Bool where
    ord false = 0
    ord true  = 1
    from 0    = false
    from _    = true           -- nonzero is true
    pred true = false
    pred _    = error "pred false"
    succ false = true
    succ true  = error "succ true"
    enumFromTo a b = case a <=> b of
        Lt -> [a,b]
        Eq -> [a]
        Gt -> []
    enumFromThen a b 
        | a != b    = [a,b]
        | otherwise = []
    enumFromThenTo a b _ =  enumFromThen a b
    enumFrom false = [false,true]
    enumFrom true  = [true]        


--############## String instances ###############

instance Eq String where
    pure native == equals :: String -> String -> Bool
    (!=) :: String -> String -> Bool
    a != b = !(a==b)

instance Ord String where
    (<=>) :: String -> String -> Ordering
    (>)   :: String -> String -> Bool
    (<)   :: String -> String -> Bool
    (>=)  :: String -> String -> Bool
    (<=)  :: String -> String -> Bool
    a <=> b = (a.compareTo b). <=>  0
    a >   b = (a.compareTo b). >    0
    a <   b = (a.compareTo b). <    0
    a >=  b = (a.compareTo b). >=   0
    a <=  b = (a.compareTo b). <=   0






--################# Char instances    #############
instance Eq  Char where
    pure native == :: Char -> Char -> Bool
    pure native != :: Char -> Char -> Bool


instance Ord Char where
    (<=>)      :: Char -> Char -> Ordering
    a <=> b = a.ord. <=> b.ord
    pure native <=  :: Char -> Char -> Bool
    pure native >=  :: Char -> Char -> Bool
    pure native <   :: Char -> Char -> Bool
    pure native >   :: Char -> Char -> Bool


instance Bounded Char where
    pure native minBound   java.lang.Character.MIN_VALUE :: Char
    pure native maxBound   java.lang.Character.MAX_VALUE :: Char

instance Enum Char where
    pure native from       "(char)" :: Int -> Char
    pred c = Char.from (Char.ord c - 1)
    succ c = Char.from (Char.ord c + 1)
    enumFromTo a b
        | a < b     = a:enumFromTo (succ a) b
        | a == b    = [a]
        | otherwise = []
    enumFrom a       = enumFromTo a maxBound
    enumFromThen !a !b = enumFromThenTo a b (if a<b then maxBound else minBound)
    enumFromThenTo !a !b c = if a<b && a<=c || a>b && a>=c
                                then goFromByTo (ord a) (ord b - ord a) (ord c)
                                else []
        where
            goFromByTo !a inc c
                | inc > 0, a < c, (c-a) < inc = [Char.from a]
                | a == c                      = [Char.from a]
                | inc < 0, a > c, (c-a) > inc = [Char.from a]
                | otherwise                   = Char.from a : goFromByTo (a+inc) inc c  


chr i = Char.from i

--- make a 'String' from a single 'Char'
pure native ctos    java.lang.Character.toString  :: Char -> String



--################# Float Instances   #############


instance Eq Float where
    pure native ==  :: Float -> Float -> Bool
    pure native !=  :: Float -> Float -> Bool

instance Ord Float where
    pure native <=  :: Float -> Float -> Bool
    pure native >=  :: Float -> Float -> Bool
    pure native <   :: Float -> Float -> Bool
    pure native >   :: Float -> Float -> Bool
    (<=>)  :: Float -> Float -> Ordering
    a <=> b = if a<b then Lt else if a>b then Gt else Eq

instance Real Float where
    pure native + :: Float -> Float -> Float
    pure native - :: Float -> Float -> Float
    pure native * :: Float -> Float -> Float
    pure native / :: Float -> Float -> Float
    zero = 0.0f
    one  = 1.0f
    pure native negate "-" :: Float -> Float
    fromInt    i = i.float
    fromInteger n = n.double.float
    fromDouble d = d.float
    pure native isInfinite java.lang.Float.isInfinite :: Float -> Bool
    pure native isNaN      java.lang.Float.isNaN      :: Float -> Bool
    


-- ################# Double Instances   #############


instance Eq  Double where
    pure native ==  :: Double -> Double -> Bool
    pure native !=  :: Double -> Double -> Bool


instance Ord Double where
    pure native <=  :: Double -> Double -> Bool
    pure native >=  :: Double -> Double -> Bool
    pure native <   :: Double -> Double -> Bool
    pure native >   :: Double -> Double -> Bool
    (<=>)  :: Double -> Double -> Ordering
    a <=> b = if a<b then Lt else if a>b then Gt else Eq



instance Real Double where
    pure native + :: Double -> Double -> Double
    pure native - :: Double -> Double -> Double
    pure native * :: Double -> Double -> Double
    pure native / :: Double -> Double -> Double
    zero = 0.0
    one = 1.0
    pure native negate "-" :: Double -> Double
    fromInt i    = i.double
    fromInteger n = n.double
    fromDouble d = d
    pure native isInfinite java.lang.Double.isInfinite :: Double -> Bool
    pure native isNaN      java.lang.Double.isNaN      :: Double -> Bool


-- ################# Misc. types and derivations #############

-- derive Show ()

-- derive Show Ordering

instance Eq a => Eq [a] where
    --- two lists are equal if their heads and tails are equal or if the lists are empty
    (a:as) == (b:bs) | a == b = as == bs 
                     | otherwise = false
    []     == []     = true
    _      == _      = false
    hashCode [] = 31
    hashCode as = loop as 32
        where 
            loop (a:as) !acc = loop as (acc*31 + hashCode a)
            loop [] acc      = acc 


-- derive Ord Ord a => [a]

data Maybe a = Nothing | Just a

{--
    The 'maybe' function takes a default value, a function, and a 'Maybe' value. 
    If the 'Maybe' value is 'Nothing', the function returns the default value. 
    Otherwise, it applies the function to the value inside the 'Just' and returns the result.
    -}

maybe d f (Just x) = f x
maybe d f Nothing  = d



data Either a b = Left a | Right b

--- apply first function to value in 'Left' or second function to value in 'Right'
either left right (Left x)  = left x
either left right (Right x) = right x


--- return the first element of a 2-tuple
fst (a, _) = a

--- return the second element of a 2-tuple
snd (_, a) = a

--- A head strict variant of (:)
--- This will be used in list comprehensions
!x !: xs = x:xs

{- more tuple stuff in Tuples.fr -}

-- function stuff

protected id x = x  -- despite Category, do not remove, it is used in code generation

{--
    @a $ b@ is the same as @a b@, but because of '$''s low precedence
    one can write @f $ x+y@ instead of @f (x+y)@. Also, because '$' is right
    associative, @f $ g $ h y@ is @f (g (h y))@
-}
(a) $ (b) = a b

--- Same as `$` but argument is strict
a $! !b = a b

--- @const a@ is a function that returns _a_ regardless of its argument.
const a _ = a

--- @asTypeOf a b@ is _a_  with the type of _b_.
--- This is a type restricted version of 'const'.
asTypeOf :: a -> a -> a
asTypeOf a _ = a

--- Exchange first and second argument of a function, i.e.
--- > flip f a b = f b a
flip f a b = f b a

--- Passes the elements of a 2-tuple as arguments to a function.
uncurry f (a,b) = f a b

--- @curry f@ passes the next two arguments as 2-tuple to _f_
curry f a b = f (a,b)


--- In patterns, the \@-operator is used to bind a name to a complex pattern
--- > f (x@a:as) = e
--- is the same as
--- > f arg = case arg of { x -> case x of { a:as -> e }}
(@) = \_ \_ -> ()


{--
 * @using f@ applies a projection function _f_ on both sides of '=='.
 * Example usage:
 * > uniqBy (using fst) [(1, 1), (2, 2), (2, 3), (3,4), (2,5)]
 -}
using f a b      =  f a == f b

{--
 * @comparing f@ applies a projection function on both sides of '<=>'.
 * Example usage:
 * > sortBy (comparing snd) [(1, "z"), (2, "b")] == [(2, "b"), (1, "z")]
 -}
comparing f a b  =  f a <=> f b

--- this is just an alias for 'comparing'
ascending = comparing

{--
 * @descending f@ applies a projection function on both sides of '<=>', but flips arguments.
 * Example usage:
 * > sortBy (descending fst) [(1, "z"), (2, "b")] == [(2, "b"), (1, "z")]
 -}
descending f a b =  f b <=> f a

-- ####################################################################
-- ###################### monad stuff #################################
-- ####################################################################

--- > g `on` f 
--- Apply a projection function @f@ on both operands of @g@
--- > comparing f = (<=>) `on` f
g `on` f = \a\b -> f a `g` f b

{--
  @(ST s a)@ is an abstract data type and is
  a computation that encapsulates side effects in state thread @s@
  and returns a value of type @a@.

  The type @s@ can be understood as a compiler generated unique index for state threads.
  Every state thread is independent of each other and keeps track of mutable variables
  created in it. For detailed information, read the paper _Lazy Functional State Threads_.

  Every mutable native data type shall be wrapped in a 'frege.prelude.PreludeIO#Mutable' 
  with phantom type parameter @s@.
  that tells to what state thread the value belongs. 
  For example, the @new@ method of
  the java class @java.util.Date@ could be accessed like this:

  > data Date s = native java.util.Date where
  >     native new :: Long -> ST s (Mutable s Date)

  Inside ST actions, Date values can be created and manipulated with
  impure native methods at will. However, such a value can never escape
  its ST thread.

  Because @ST s@ is an instance of 'frege.prelude.PreludeMonad#Monad', ST actions can be combined, which
  ensures sequenced execution. For example, we could add another method
  to the Date type that converts the date to a string:
  >     native toString :: Mutable s Date -> ST s String
  
  and a computation which yields the current time in string form:
  
  > epoch = do
  >    date <- Date.new 0L
  >    return date.toString
  
  This looks almost like java already! @epoch@ has type @ST s String@ and we can run
  the computation with @epoch.run@ (see 'ST.run' below), 
  which gives us a nice, pure, immutable,
  functional, correct 'String' value.

  The 'IO' type is just an alias for 'ST' 'RealWorld', and can be thought of as
  indexing a unique global state thread.
  Values of type 'IO' @a@ are also called  _IO actions_.

  Any ST value can also be used in the IO thread.

  This guarantees that
  - any computation with side effect is sequenced through the ST-Monad
  - any function whose return type is not @IO something@ does not have side effects,
    as long as no impure native function or value is deliberately declared to be pure.

 -}

{--
   A 'NonEmpty' is like a list, but never empty.
-}
protected data NonEmpty a = NonEmpty {
  neHead :: a,  --- The head of the non-empty list.
  neTail :: [a] --- The tail of the non-empty list.
}

abstract newtype ST s a = ST (s -> a)   where
    {-- nowarn: performUnsafe
    
     Run a stateful action with type @ST r a@ and return a result of type _a_.
     The overall computation @ST.run st@ is pure, though inside the 'ST' action
     local mutable state can be employed.
     
     This is possible only if the result type @a@ of the state action does *not* mention
     @r@ and if @r@ is a type variable. Hence, it is not possible to 'ST.run' an 'IO' action.
     -}
    public run :: forall a . (forall ß. ST ß a) -> a
    public run stx = case  stx of
        ST x   → x ()


    --- warning: You are breaking the rules. Expect an arbitrary result and program crashes.
    public performUnsafe ∷ IO a → a
    public performUnsafe (ST f)  = f RealWorld.rw


    public return a = ST (\_ → a)


    public (>>=) ∷ ST u a → (a→ST u b) → ST u b
    public ST f >>= k = ST (\u → case f u of
            !v -> case k v of
                ST g → g u
        )

 
{--
 * This abstract data type identifies the global state (disk, network, you name it).
 * Values of type 'ST' 'RealWorld' @a@ are likely to perform input/output, manipulate
 * global data and so on.
 -}
data RealWorld = pure native frege.runtime.Phantom.RealWorld where
    private pure native rw frege.runtime.Phantom.theRealWorld :: RealWorld

--- @IO a@ is an abbreviation for 'ST' 'RealWorld' @a@
type IO = ST RealWorld



--- warning: use @stderr.print@ instead        
--- print a 'String' to the standard error stream
native traceStr java.lang.System.err.print     :: String -> IO ()

--- warning: use @stderr.println@ instead
--- print a 'String' to the standard error stream and append a new line.
native traceStrLn java.lang.System.err.println     :: String -> IO ()

--- warning: use @stdout.print@ instead
--- print a 'String' to the standard output stream
native printStr java.lang.System.out.print     :: String -> IO ()

--- warning: use @stdout.println@ instead
--- print a 'String' to the standard output stream and append a new line.
native printStrLn java.lang.System.out.println :: String -> IO ()

-- Some native definitions we need ...

native module where {
    @SuppressWarnings("unchecked") final public static<A> A polyCharAt(String s, int at) {
        final java.lang.Character c = s.charAt(at);
        return (A)(Object)c;
    }
    /**
     * <p>Wrapper for Checked Exceptions</p>
     * 
     * <p>Because we cannot simply re-throw checked exceptions,
     * we must wrap checked exceptions when we catch them.</p>
     *
     * <p> Contains also support for catch (i.e. doCatch)</p>
     * 
     * @author ingo
     */
    public static class WrappedCheckedException extends frege.runtime.Undefined {
        /**
         * Construct a wrapped exception from a Throwable.
         */
        public WrappedCheckedException(Throwable cause) {
            super("", cause);
        }

        /**
         * Everything that is an  unchecked exception 
         * (subtype of {@link java.lang.RuntimeException}) needs no wrapping. 
         */
        public final static RuntimeException wrapIfNeeded(final RuntimeException ex) {
            return ex;
        }

        /**
         * Everything that is an  error 
         * (subtype of {@link java.lang.Error}) needs no wrapping. 
         */
        public final static Error wrapIfNeeded(final Error ex) {
            return ex;
        }

        /**
         * Construct a wrapped exception from a checked exception 
         * 
         */
        public final static WrappedCheckedException wrapIfNeeded(final Throwable ex) {
            if (ex instanceof WrappedCheckedException) {
                return (WrappedCheckedException)ex;
            }
            return new WrappedCheckedException(ex);
        }

        /**
         * <p>Run an IO action and invoke the handler on exceptions.</p>
         * <p>The frege type of this function is</p>
         * <code>native catch :: Class e -> IO a -> (e -> IO a) -> IO a</code>  
         */
        public static<E,A,S> A doCatch(Class<E> cls,
                Func.U<S,A> action, 
                Func.U<E, Func.U<S,A>> handler) {

            try {
                final Func.U<Object,A> ia = RunTM.<Func.U<Object,A>>cast(action);
                // System.out.println("entering try for " + cls.getName());
                return PreludeBase.TST.<A>run(ia).call();
            } catch (WrappedCheckedException e) {
                final Throwable exc = e.getCause();
                // System.out.println("entering catch for Wrapped with " + exc.getClass().getName());
                if (cls.isInstance(exc)) {
                    @SuppressWarnings("unchecked") final E eexc = (E) exc;
                    final Func.U<Object,A> ih1 
                                = RunTM.<Func.U<Object,A>>cast(
                                                            handler.apply(Thunk.<E>lazy(eexc))
                                                                .call());
                    return PreludeBase.TST.<A>run(ih1).call();
                }
                throw e;    // go to next catch, if any
            } catch (Throwable exc) {
                // System.out.println("entering catch for " + exc.getClass().getName());
                if (cls.isInstance(exc)) {
                    @SuppressWarnings("unchecked") final E eexc = (E) exc;
                    final Func.U<Object,A> ih2 
                                = RunTM.<Func.U<Object,A>>cast(
                                                            handler.apply(Thunk.<E>lazy(eexc))
                                                                .call());

                    return PreludeBase.TST.<A>run(ih2).call();
                }
                // java6 does not allow rethrowing exc here
                if (exc instanceof RuntimeException) 
                    throw (RuntimeException) exc;
                if (exc instanceof Error)
                    throw (Error) exc;
                throw wrapIfNeeded(exc);    // go to next catch, if any
            }
        }

        /**
         * <p>Run an ST action but make sure another one is run, even if the first one
         * is interrupted.</p>
         */
        public static<S,A,B> A doFinally(
                Func.U<S,A> result,
                Func.U<S,B> after) {
            final A r;
            try {
                final Func.U<Object,A> ia = RunTM.<Func.U<Object,A>>cast(result);
                r = PreludeBase.TST.<A>run(ia).call();
            }
            finally  {
                final Func.U<Object,B> ib = RunTM.<Func.U<Object,B>>cast(after);
                final B b = PreludeBase.TST.<B>run(ib).call();
            }
            return r;
        }

        /**
         * <p> Throw exception from monadic code.</p>
         */
        public static void throwST(Throwable t) {
            throw wrapIfNeeded(t);
        }
    }
}
